package com.xcm.filter;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.xcm.config.CustomProperties;
import com.xcm.constant.SSOFilterConstant;
import com.xcm.util.DESUtils;
import com.xcm.util.RestClientUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录验证filter
 */
public class SSOLoginFilter implements Filter {
	private String cookieName;
	private String ssoServerUrl;
	private String platformTag;
	private String secretKey;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		ServletContext servletContext = filterConfig.getServletContext();
		WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
		CustomProperties customProperties = (CustomProperties) webApplicationContext.getBean("customProperties");
		cookieName = customProperties.getCookieName();
		ssoServerUrl = customProperties.getSsoLoginUrl();
		platformTag = customProperties.getPlatformTag();
		secretKey = customProperties.getSecretKey();
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		//上下文路径
		String path = request.getContextPath();
		//gotoURL
		String gotoURL = request.getParameter(SSOFilterConstant.SSO_FILTER_GOTOURL);
		if (gotoURL == null) {
			gotoURL = request.getRequestURL().toString();
		}
		StringBuilder urlSb = new StringBuilder();
		//setCookieURL
		String setCookieURL = urlSb.append(request.getScheme()).append("://").append(request.getServerName())
				.append(":").append(request.getServerPort()).append(path).append("/setCookie").toString();
		//重置urlSb
		urlSb.setLength(0);
		urlSb.append(ssoServerUrl).append("preLogin?setCookieURL=").append(DESUtils.encrypt(setCookieURL, secretKey))
				.append("&gotoURL=").append(DESUtils.encrypt(gotoURL, secretKey)).append("&platformTag=").append(platformTag);
		String url = urlSb.toString();

		Cookie ticket = null;
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if (cookie.getName().equals(cookieName)) {
					ticket = cookie;
					break;
				}
			}
		}
		String requestURI = request.getRequestURI();
		// TODO 放开下载文件url
		if(requestURI.contains("/file/download")){
			chain.doFilter(req, resp);
			return;
		}
		if (requestURI.equals(path + "/logout")) {
			doLogout(ticket, response);
			//注销成功，重定向到登录界面，登录成功，默认跳转到首页
			//重置urlSb
			urlSb.setLength(0);
			gotoURL = urlSb.append(request.getScheme()).append("://")
					.append(request.getServerName()).append(":").append(request.getServerPort())
					.append(path).append("/index").toString();
			//重置urlSb
			urlSb.setLength(0);
			urlSb.append(ssoServerUrl).append("preLogin?setCookieURL=").append(DESUtils.encrypt(setCookieURL, secretKey))
					.append("&gotoURL=").append(DESUtils.encrypt(gotoURL, secretKey)).append("&platformTag=").append(platformTag);
			response.sendRedirect(urlSb.toString());
			return;
		} else if (requestURI.equals(path + "/setCookie")) {
			setCookie(request, response);
		} else if (ticket != null) {
			authCookie(request, response, chain, ticket, path, setCookieURL, gotoURL);
		} else if (requestURI.contains(path + "/file/download/")) {
			// TODO: 2018/5/10 终端下载apk，以后可能会把apk上传到华为云，现在没有校验，直接放行 
			chain.doFilter(request, response);
		} else {
			response.sendRedirect(url);
		}
		return;
	}

	/**
	 * 验证Cookie
	 */
	private void authCookie(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Cookie ticket, String path, String setCookieURL, String gotoURL) throws ServletException, IOException {
		Map<String, Object> params = new HashMap<>();
		String ticketValue = ticket.getValue();
		params.put(SSOFilterConstant.SSO_FILTER_TICKET, ticketValue);
		StringBuilder urlSb = new StringBuilder(ssoServerUrl).append("authTicket");
		String url = urlSb.toString();
		try {
			JSONObject result = post(url, params);
			int code = result.getIntValue("code");
			if (SSOFilterConstant.CODE_SUCCESS == code) {
				//把cookie放入request中，需要获取用户信息，从request取出cookie值，去redis从获取用户的信息
				request.setAttribute(cookieName, ticketValue);
				chain.doFilter(request, response);
				return;
			} else {
				//验证失败，返回登录界面
				urlSb.setLength(0);
				urlSb.append(ssoServerUrl).append("preLogin?setCookieURL=").append(DESUtils.encrypt(setCookieURL, secretKey))
						.append("&gotoURL=").append(DESUtils.encrypt(gotoURL, secretKey)).append("&platformTag=").append(platformTag);
				response.sendRedirect(urlSb.toString());
				return;
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设置Cookie
	 */
	private void setCookie(HttpServletRequest request, HttpServletResponse response) throws IOException {
		Cookie ticket = new Cookie(cookieName, request.getParameter(SSOFilterConstant.SSO_FILTER_TICKET));
		ticket.setPath("/");
		ticket.setMaxAge(Integer.parseInt(request.getParameter(SSOFilterConstant.SSO_FILTER_EXPIRY)));
		response.addCookie(ticket);

		String gotoURL = request.getParameter(SSOFilterConstant.SSO_FILTER_GOTOURL);
		if (gotoURL != null) {
			response.sendRedirect(DESUtils.decrypt(gotoURL, secretKey));
		}
	}

	/**
	 * 注销
	 */
	private void doLogout(Cookie ticket, HttpServletResponse response) throws IOException {
		Map<String, Object> params = new HashMap<>();
		params.put(SSOFilterConstant.SSO_FILTER_COOKIENAME, ticket.getValue());

		StringBuilder urlSb = new StringBuilder();
		String url = urlSb.append(ssoServerUrl).append("logout").toString();
		try {
			JSONObject result = post(url, params);
			int code = result.getIntValue("code");
			//注销成功，删除cookie
			if (SSOFilterConstant.CODE_SUCCESS == code) {
				ticket.setValue(null);
				ticket.setMaxAge(0);
				ticket.setPath("/");
				response.addCookie(ticket);
			}
		} catch (JSONException e) {
			throw new RuntimeException(e);
		}
	}

	private JSONObject post(String url, Map<String, Object> params) throws JSONException {
		String post = RestClientUtils.post(url, params, "UTF-8");
		return JSON.parseObject(post);
	}

	@Override
	public void destroy() {

	}
}
